// 本文件用于：路由
import { RootState } from '@/store';
import { ComponentType, lazy, LazyExoticComponent, Suspense, useMemo } from 'react';
import { useSelector } from 'react-redux';
import { Route, Routes } from 'react-router-dom';
import { JSX } from 'react/jsx-runtime';
import Fallback from './fallback';
import staticRouter from './static-router';

export default () => {
  /** 用户有权限访问的菜单 */
  const userMenu = useSelector((state: RootState) => state.user.userMenu);

  /**
   * 懒加载指定的组件
   * 这个index.tsx结尾，是必要的，来自vite的要求
   * @param name 要加载的组件文件夹名称
   * @param isChild 是否是子路由
   * @returns
   */
  const dynamicImport = (name: string, isChild: boolean) => {

    // https://github.com/vitejs/vite/issues/4945
    // https://stackoverflow.com/questions/77330284/vite-lazy-import-multilevel-directory
    // https://github.com/rollup/plugins/tree/master/packages/dynamic-import-vars#limitations

    const _nr = name.split('/');
    // 兜底的loading最少要展示多少秒
    const minFallbackTime = isChild ? 0 : 600;
    let DI: LazyExoticComponent<ComponentType<any>> | JSX.IntrinsicAttributes;

    // vite中，动态引入时，如果再import方法中传入的是模板字符串，会对模板字符串进行分析，进而进行一些优化
    // 但是传入模板字符串时，需要指定有多少级的目录，所以这里写死了最多五级的引入
    // 再多的级别，就直接用变量引入了
    // 但是说实话，不知道优化了什么，因为直接引入变量，也是有树摇的
    if (_nr.length === 1) {
      DI = lazy(async () => {
        // 用Promise，控制界面的最低加载时间，防止loading动画一闪而过
        const [moduleExports] = await Promise.all([
          import(`../views/${name}/index.tsx`),
          new Promise((resolve) => setTimeout(resolve, minFallbackTime)),
        ]);
        return moduleExports;
      });
    } else if (_nr.length === 2) {
      DI = lazy(async () => {
        const [moduleExports] = await Promise.all([
          import(`../views/${_nr[0]}/${_nr[1]}/index.tsx`),
          new Promise((resolve) => setTimeout(resolve, minFallbackTime)),
        ]);
        return moduleExports;
      });
    } else if (_nr.length === 3) {
      DI = lazy(async () => {
        const [moduleExports] = await Promise.all([
          import(`../views/${_nr[0]}/${_nr[1]}/${_nr[2]}/index.tsx`),
          new Promise((resolve) => setTimeout(resolve, minFallbackTime)),
        ]);
        return moduleExports;
      });
    } else if (_nr.length === 4) {
      DI = lazy(async () => {
        const [moduleExports] = await Promise.all([
          import(`../views/${_nr[0]}/${_nr[1]}/${_nr[2]}/${_nr[3]}/index.tsx`),
          new Promise((resolve) => setTimeout(resolve, minFallbackTime)),
        ]);
        return moduleExports;
      });
    } else if (_nr.length === 5) {
      DI = lazy(async () => {
        const [moduleExports] = await Promise.all([
          import(`../views/${_nr[0]}/${_nr[1]}/${_nr[2]}/${_nr[3]}/${_nr[4]}/index.tsx`),
          new Promise((resolve) => setTimeout(resolve, minFallbackTime)),
        ]);
        return moduleExports;
      });
    } else {
      const allStr = `../views/${name}/index.tsx`;
      DI = lazy(async () => {
        const [moduleExports] = await Promise.all([
          import(/* @vite-ignore */ allStr),
          new Promise((resolve) => setTimeout(resolve, minFallbackTime)),
        ]);
        return moduleExports;
      });
    }

    return <DI></DI>;
  };

  const genRouter = (routeArr: any[]) => {
    const _genRouter = (_routeArr: any[], isChild: boolean): any => {
      return _routeArr.map((item) => {
        if (item.children && item.children.length) {
          return (
            <Route key={item.path} path={item.path} element={dynamicImport(item.compPath, isChild)}>
              {_genRouter(item.children, true)}
            </Route>
          );
        } else {
          return (
            <Route
              key={item.path}
              path={item.path}
              element={dynamicImport(item.compPath, isChild)}
            ></Route>
          );
        }
      });
    };

    return _genRouter(routeArr, false);
  };

  const renderRouter = useMemo(() => {
    const mixMenu = staticRouter.concat(userMenu);
    return genRouter(mixMenu);
  }, [staticRouter, userMenu]);

  return (
    <Suspense fallback={<Fallback />}>
      <Routes>{renderRouter}</Routes>
    </Suspense>
  );
};
